﻿// 테스트용 등록 폼을 사용하려면 아래 주석을 풀 것
//#define REGISTERATION_TEST

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Manina.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Xml;
using System.Xml.XPath;
using System.Runtime.InteropServices;
using System.IO.MemoryMappedFiles;
//using OpenCvSharp;

namespace LicenseAutoDetection
{
    public enum Result
    {
        Passed,
        Ignored
    }

    public enum ViewMode
    {
        Thumbnail,
        Gallery,
        Preview,
        Detail
    }

    public enum ViewStyle
    {
        Basic,
        Tile
    }

    public enum ThumbSize
    {
        Size36 = 36,
        Size48 = 48,
        Size72 = 72,
        Size96 = 96,
        Size120 = 120,
        Size144 = 144,
        Size168 = 168,
        Size192 = 192
    }

    public enum SearchDepth
    {
        One,
        All
    }

    public enum OSVersion
    {
        None,
        Windows95,
        Windows98,
        WindowsMe,
        WindowsNT,
        Windows2000,
        WindowsXP,
        WindowsServer2003,
        WindowsVista,
        Windows7,
        Windows8
    }

    public enum InfoType
    {
        Identification,
        Contract,
        ResidentNum,
        PhoneNum,
        AccountNum,
        CardNum
    }

    public partial class MainForm : Form
    {
        public static readonly string RootDir = "컴퓨터"; 
        const string Seperator = "\\";


        TreeNode rootNode;
        SearchTask searchTask;
        DeleteTask deleteTask;
        Settings settings;
        public IgnoreFileList ignoreFileList;
        public TransData transData; 
        System.Windows.Forms.Timer timer;

        public List<string> AllSearched;            // 검색된 파일들
        public List<string> SearchedNotSelected;    // 분석 후 검색되었지만 선별되지 못한 파일들
        public List<string> Selected;               // 분석 후 선별된 파일들
        public List<string> SelectedNotPassed;      // 분석 후 선별되었지만 검출되지 못한 파일들
        public List<string> Passed;                 // 분석 후 검출된 파일들
        
        private string SelectedPath
        {
            get
            {
                if (treeView.SelectedNode == null)
                {
                    return settings.Path;
                }
                else
                {
                    string path = treeView.SelectedNode.FullPath;
                    return path.Equals(RootDir) ? path : path.Substring(RootDir.Length + Seperator.Length).Replace("\\\\", "\\");
                }
            }
        }

        public ImageListView ImageListView
        {
            get
            {
                return imageListView;
            }
        }

        #region Operating System Check
        private bool GetWindowsVersion()
        {
            OperatingSystem os = Environment.OSVersion;
            //OSVersion winVersion = OSVersion.None;

            switch (os.Platform)
            {
                case PlatformID.MacOSX:
                case PlatformID.Unix:
                case PlatformID.WinCE:
                case PlatformID.Xbox:
                case PlatformID.Win32S:
                case PlatformID.Win32Windows:
                    MessageBox.Show("해당 PC의 운영체제를 지원하지 않습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;

                case PlatformID.Win32NT:
                    if (os.Version.Major == 4) // OSVersion.WindowsNT;
                    {
                        return true;
                    }
                    else if (os.Version.Major == 5)
                    {
                        switch (os.Version.Minor)
                        {
                            case 0:  // OSVersion.Windows2000;
                            case 1:  // OSVersion.WindowsXP;
                            case 2:  // OSVersion.WindowsServer2003;
                                return true;
                        }
                    }
                    else if (os.Version.Major == 6)
                    {
                        switch (os.Version.Minor)
                        {
                            case 0:  // OSVersion.WindowsVista;
                            case 1:  // OSVersion.Windows7;
                            case 2:  // OSVersion.Windows8;
                                return true;
                        }
                    }
                    break;
            }
            MessageBox.Show("해당 PC의 운영체제 정보를 받아올 수 없습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return false;
        }
        #endregion

        #region Init
        private void InitOperatingSystem()
        {
            if (!GetWindowsVersion())
            {
                searchTask.Cancel();
                deleteTask.Cancel();
                Application.Exit();
            }
        }

        private void InitTreeView()
        {
            // 루트 노트 생성
            rootNode = new TreeNode(RootDir);
            treeView.Nodes.Add(rootNode);
            rootNode.ImageIndex = 0;
            rootNode.SelectedImageIndex = 0;
            rootNode.Name = RootDir;
            FillNode(rootNode);

            // 시작 경로로 확장
            ExpandNode(SelectedPath);
        }

        private void ExpandNode(string selectedPath)
        {
            string path = RootDir;
            string[] toks = selectedPath.Split('\\');
            TreeNode selected = rootNode;

            // treeView.selectedNode에 값을 설정할 때 treeView_BeforeExpand()가 호출되어 FillNode()로 selected 노드에 디렉토리 정보가 채워짐
            treeView.SelectedNode = selected;
            selected.Expand();

            foreach (string tok in toks)
            {
                path += "\\" + tok + (tok.EndsWith(":") ? "\\" : "");
                TreeNode[] nodes = selected.Nodes.Find(path, false);

                if (nodes.Length > 0)
                {
                    selected = nodes[0];
                    treeView.SelectedNode = selected;
                    selected.Expand();
                }
                else
                {
                    break;
                }
            }
        }

        private void InitListViewImg()
        {
            UpdateViewMenuState(settings.View);
            UpdateStyleMenuState(settings.Style);
            UpdateResultTypeMenuState(Result.Passed);
            UpdateMenuStateByStart(false);
            UpdateThumbSizeMenuState(settings.ThumbnailSize);
            UpdateSearchMenuState(settings.SearchDepth, false);
        }

        private void InitTimer()
        {
            // 타이머 생성
            timer = new System.Windows.Forms.Timer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = 60 * 40000 * 6; // 4시간
            timer.Start();
        }

        public MainForm()
        {
            InitializeComponent();

            settings = new Settings();
            ignoreFileList = new IgnoreFileList();
            searchTask = new SearchTask(settings, this);
            deleteTask = new DeleteTask(this);

            AllSearched = new List<string>();
            SearchedNotSelected = new List<string>();
            Selected = new List<string>();
            SelectedNotPassed = new List<string>();
            Passed = new List<string>();
        }

        public void ClearPathList(Boolean all)
        {
            if (all)
                AllSearched.Clear();

            SearchedNotSelected.Clear();
            Selected.Clear();
            SelectedNotPassed.Clear();
            Passed.Clear();
        }
        #endregion

        #region Events
        private void MainForm_Load(object sender, EventArgs e)
        {
            InitOperatingSystem();
            InitListViewImg();
            InitTreeView();

            transData = new TransData();    //connect 여부

            if (transData.outData[23] != 1)
            {
#if (REGISTERATION_TEST)
                using (RegistrationForm_Test registrationForm = new RegistrationForm_Test())
#else
                using (RegistrationForm registrationForm = new RegistrationForm())
#endif
                {
                    while (true)
                    {
                        if (registrationForm.ShowDialog(this) == DialogResult.OK)
                        {
                            if (registrationForm.complete)
                            {
                                break;
                            }
                        }
                        else
                        {
                            searchTask.Cancel();
                            deleteTask.Cancel();
                            Application.Exit();
                            return;
                        }
                    }
                }
            }

            UpdateMenuStateByStart(false);
            UpdateSearchMenuState(SearchDepth.All, true);
            InitTimer();
        }
        
        private void treeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            FillNode(e.Node);
        }

        private void FillNode(TreeNode node, Boolean isChild = false)
        {
            node.Nodes.Clear();

            if (node.Name.Equals(RootDir)) // 루트 노드인 경우 드라이브 추가
            {
                foreach (DriveInfo drive in DriveInfo.GetDrives())
                {
                    if (drive.Name.Equals(settings.IgnorePath))
                    {
                        continue;
                    }

                    if (drive.IsReady == true)
                    {
                        TreeNode child = new TreeNode(drive.Name);
                        node.Nodes.Add(child);
                        child.ImageIndex = 1;
                        child.SelectedImageIndex = 1;
                        child.Name = child.FullPath;

                        if (!isChild)
                            FillNode(child, true);
                    }
                }
            }
            else // 루트 노드가 아니면 디렉토리 추가
            {
                string path = node.Name.Substring(RootDir.Length + Seperator.Length).Replace("\\\\", "\\");
                DirectoryInfo dirinfo = new DirectoryInfo(path);
                DirectoryInfo[] dirs;

                try
                {
                    dirs = dirinfo.GetDirectories();
                }
                catch
                {
                    return;
                }

                foreach (DirectoryInfo dir in dirs)
                {
                    FileInfo fileinfo;

                    if (settings.ExcludeFolder(dir.FullName))
                    {
                        continue;
                    }

                    try
                    {
                        fileinfo = new FileInfo(dir.FullName);
                    }
                    catch
                    {
                        continue;
                    }

                    if ((fileinfo.Attributes & FileAttributes.System) != FileAttributes.System &&
                        (settings.IncludeHidden || (fileinfo.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden))
                    {
                        TreeNode child = new TreeNode(fileinfo.Name);
                        node.Nodes.Add(child);
                        child.ImageIndex = 2;
                        child.SelectedImageIndex = 2;
                        child.Name = child.FullPath;

                        if (!isChild)
                            FillNode(child, true);
                    }
                }
            }
        }

        // 이미지 리스트 뷰 아이템 선택 시
        private void imageListView_SelectionChanged(object sender, EventArgs e)
        {
            UpdateSelectResetMenuState(!searchTask.IsCompleted || !deleteTask.IsCompleted);
            UpdateStatusStrip(String.Format("{0}개 중 {1}개가 선택되었습니다.", imageListView.Items.Count, imageListView.SelectedItems.Count), null, -2);
        }

        // 이미지 리스트 뷰에서 키 처리
        private void imageListView_KeyDown(object sender, KeyEventArgs e)
        {
            if (imageListView.SelectedItems.Count <= 1 && imageListView.Items.FocusedItem != null && e.KeyCode == Keys.Space)
            {
                imageListView.Items.FocusedItem.Selected = !imageListView.Items.FocusedItem.Selected;
                imageListView.Refresh();
            }
        }

        // 검색이나 분석 중에 Esc 키로 취소
        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                searchTask.Cancel();
                deleteTask.Cancel();
            }
        }

        private void MainForm_Closing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;        // 종료 이벤트 취소
                this.Visible = false;
            }
        }

        private void MainForm_Closed(object sender, FormClosedEventArgs e)
        {
            searchTask.Cancel();
            deleteTask.Cancel();
        }
        #endregion

        #region 메인 폼 컨트롤 업데이트
        // v1: 상태바의 첫번째 라벨. 경로가 표시됨. null이면 변경하지 않음
        // v2: 작업 상태. "작업중"이나 "작업완료"가 표시됨. null이면 변경하지 않음
        // v3: progress 바. 0 이상의 값은 진행 단계를, -1은 indeterminate 상태를, 그 이외의 값이면 변경하지 않음
        public void UpdateStatusStrip(string v1, string v2, int v3)
        {
            if (v1 != null)
                toolStripStatusLabel1.Text = v1;

            v3 = Math.Min(v3, 100);

            if (v3 > 0)
            {
                v2 = String.Format("{0} ({1}%)", v2 != null ? v2 : toolStripStatusLabel2.Text, v3);
            }

            if (v2 != null)
                toolStripStatusLabel2.Text = v2;

            if (v3 == -1)
            {
                toolStripProgressBar3.Style = ProgressBarStyle.Marquee;
            }
            else if (v3 >= 0)
            {
                toolStripProgressBar3.Style = ProgressBarStyle.Continuous;
                toolStripProgressBar3.Value = v3;
            }
        }

        public void UpdateNotifyIcon(string text)
        {
            try
            {
                ladnotifyIcon.ShowBalloonTip(0, "검색 완료", text, ToolTipIcon.Info);
            }
            catch
            {

            }
        }

        // 시작/정지에 따라 메뉴 활성화 변경
        public void UpdateMenuStateByStart(Boolean start)
        {
            UpdateStartStopMenuState(start);
            UpdateSelectResetMenuState(start);
        }

        // 이미지 리스트 뷰에 아이템 존재 여부에 따라 모두 선택, 선택 해제, 삭제 등의 메뉴 활성화 변경
        private void UpdateSelectResetMenuState(Boolean start)
        {
            if (start)
            {
                selectAllToolStripMenuItem.Enabled = selectAllToolStripButton.Enabled = selectAllToolStripContextMenuItem.Enabled =
                resetToolStripMenuItem.Enabled = resetToolStripButton.Enabled = resetToolStripContextMenuItem1.Enabled =
                ignoreFileAddToolStripMenuItem.Enabled = ignoreFileAddToolStripContextMenuItem.Enabled =
                ignoreFileDelToolStripMenuItem.Enabled = ignoreFileDelToolStripContextMenuItem.Enabled =
                deleteToolStripMenuItem.Enabled = deleteToolStripButton.Enabled = deleteToolStripContextMenuItem.Enabled = false;
            }
            else
            {
                Boolean all = (imageListView.Items.Count == imageListView.SelectedItems.Count);
                Boolean none = (imageListView.SelectedItems.Count == 0);
                
                selectAllToolStripMenuItem.Enabled = selectAllToolStripButton.Enabled = selectAllToolStripContextMenuItem.Enabled = !all;
                resetToolStripMenuItem.Enabled = resetToolStripButton.Enabled = resetToolStripContextMenuItem1.Enabled = !none;
                deleteToolStripMenuItem.Enabled = deleteToolStripButton.Enabled = deleteToolStripContextMenuItem.Enabled = !none;
                ignoreFileAddToolStripMenuItem.Enabled = ignoreFileAddToolStripContextMenuItem.Enabled = (!none && !viewIgnoredToolStripMenuItem.Checked);
                ignoreFileDelToolStripMenuItem.Enabled = ignoreFileDelToolStripContextMenuItem.Enabled = (!none && viewIgnoredToolStripMenuItem.Checked);
            }
        }

        // 검색, 분석, 정지 메뉴 활성화 변경
        private void UpdateStartStopMenuState(Boolean start)
        {
            searchToolStripButton.Enabled = searchToolStripMenuItem.Enabled = !start;
            stopToolStripButton.Enabled = stopToolStripMenuItem.Enabled = start;
            resultTexttoolStripLabel.Enabled = !start;
            viewResultToolStripDropDownButton.Enabled = !start;
        }

        // 이미지 리스트 뷰에 보여지는 결과 종류에 따라 메뉴 활성화 변경
        public void UpdateResultTypeMenuState(Result type)
        {
            imageListView.Items.Clear();

            if (type == Result.Ignored)
            {
                imageListView.Items.AddRange(ignoreFileList.View());
                resultTexttoolStripLabel.Text = viewIgnored2ToolStripMenuItem.Text;
            }
            else //if (type == Result.Passed)
            {
                imageListView.Items.AddRange(Passed.ToArray());
                resultTexttoolStripLabel.Text = viewPassed2ToolStripMenuItem.Text;
            }

            UpdateStatusStrip(String.Format("{0}개 파일들", imageListView.Items.Count), null, -2);

            viewPassedToolStripMenuItem.Checked = viewPassed2ToolStripMenuItem.Checked = (type == Result.Passed);
            viewIgnoredToolStripMenuItem.Checked = viewIgnored2ToolStripMenuItem.Checked = (type == Result.Ignored);
        }

        // 이미지 리스트 뷰에서 이미지 삭제 및 결과 파일 리스트에서도 삭제
        public void RemoveImageListViewItem(ImageListViewItem item)
        {
            imageListView.Items.Remove(item);

            AllSearched.Remove(item.FileName);
            Passed.Remove(item.FileName);
            SearchedNotSelected.Remove(item.FileName);
            Selected.Remove(item.FileName);
            SelectedNotPassed.Remove(item.FileName);
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (!deleteTask.IsCompleted || !searchTask.IsCompleted)
                return;

            treeView.SelectedNode = rootNode;
            UpdateSearchMenuState(SearchDepth.All, true);
            ladnotifyIcon.ShowBalloonTip(0, "예약 검사", "예약 검사를 시작합니다", ToolTipIcon.Info);
        }
        #endregion

        #region Menu
        // 파일 검색
        private void searchToolStripButton_ButtonClick(object sender, EventArgs e)
        {
            UpdateSearchMenuState(searchAllToolStripMenuItem.Checked ? SearchDepth.All : SearchDepth.One, true);
        }

        private void searchCurrentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateSearchMenuState(SearchDepth.One, true);
        }

        private void searchAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateSearchMenuState(SearchDepth.All, true);
        }

        private void UpdateSearchMenuState(SearchDepth depth, Boolean search)
        {
            if (!deleteTask.IsCompleted)
                return;

            ClearPathList(true);

            if (search)
                searchTask.Start(SelectedPath, depth == SearchDepth.All);

            searchCurrentToolStripMenuItem.Checked = searchCurrentToolStripMenuItem2.Checked = (depth == SearchDepth.One);
            searchAllToolStripMenuItem.Checked = searchAllToolStripMenuItem2.Checked = (depth == SearchDepth.All);

            settings.SearchDepth = depth;
            settings.Save();
        }

        // 정지
        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            searchTask.Cancel();
            deleteTask.Cancel();
        }

        // 검출된 파일들 보기
        private void viewPassedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateResultTypeMenuState(Result.Passed);
        }

        // 무시된 파일들 보기
        private void viewIgnoredToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateResultTypeMenuState(Result.Ignored);
        }

        // 모두 선택
        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            imageListView.SelectAll();
            UpdateStatusStrip(String.Format("{0}개 중 {1}개가 선택되었습니다.", imageListView.Items.Count, imageListView.SelectedItems.Count), null, -2);
        }

        // 모두 선택 안함
        private void resetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            imageListView.ClearSelection();
            UpdateStatusStrip(String.Format("{0}개 중 {1}개가 선택되었습니다.", imageListView.Items.Count, imageListView.SelectedItems.Count), null, -2);
        }

        // 삭제
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (imageListView.SelectedItems.Count == 0)
                return;

            if (!searchTask.IsCompleted)
                return;

            string text = string.Format("{0}개의 이미지를 삭제하려고 합니다.\n휴지통으로 옮기지 않고 바로 삭제하기에 복구할 수 없습니다.\n정말 삭제하시겠습까?", imageListView.SelectedItems.Count);

            if (MessageBox.Show(text, "삭제 확인", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                deleteTask.Start(SelectedPath);
            }
        }

        // 선택된 파일 무시하기
        private void ignoreFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (ImageListViewItem item in ImageListView.SelectedItems)
            {
                string src = item.FileName;
                ignoreFileList.addIgnoreFile(src);
                RemoveImageListViewItem(item);
                transData.IgnoredAdd = item.FileName;
            }
            transData.TransmissionIgnored();
            transData.IgnoredClear();

            ignoreFileList.Save();
        }

        // 선택된 파일 무시하지 않기
        private void ignoreFileDelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (ImageListViewItem item in ImageListView.SelectedItems)
            {
                try
                {
                    ignoreFileList.Delete(item.FileName);
                    RemoveImageListViewItem(item);
                }
                catch
                {

                }
            }
            ignoreFileList.Save();
        }

        // 끝내기
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            searchTask.Cancel();
            deleteTask.Cancel();
            Application.Exit();
        }

        // 썸네일로 보기
        private void viewThumbnailToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateViewMenuState(ViewMode.Thumbnail);
        }

        // 갤러리로 보기
        private void viewGalleryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateViewMenuState(ViewMode.Gallery);
        }

        // 프리뷰로 보기
        private void viewPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateViewMenuState(ViewMode.Preview);
        }

        // 자세히 보기
        private void viewDetailToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateViewMenuState(ViewMode.Detail);
        }

        private void UpdateViewMenuState(ViewMode mode)
        {
            if (mode == ViewMode.Thumbnail)
                imageListView.View = Manina.Windows.Forms.View.Thumbnails;
            else if (mode == ViewMode.Gallery)
                imageListView.View = Manina.Windows.Forms.View.Gallery;
            else if (mode == ViewMode.Preview)
                imageListView.View = Manina.Windows.Forms.View.Pane;
            else
                imageListView.View = Manina.Windows.Forms.View.Details;

            thumbnailToolStripButton.Checked = thumbnailToolStripMenuItem.Checked = (mode == ViewMode.Thumbnail);
            galleryToolStripButton.Checked = galleryToolStripMenuItem.Checked = (mode == ViewMode.Gallery);
            previewToolStripButton.Checked = previewToolStripMenuItem.Checked = (mode == ViewMode.Preview);
            detailToolStripButton.Checked = detailToolStripMenuItem.Checked = (mode == ViewMode.Detail);

            settings.View = mode;
            settings.Save();
        }

        // 기본 스타일
        private void basicStyleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateStyleMenuState(ViewStyle.Basic);
        }

        // 타일 스타일
        private void tilesStyleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateStyleMenuState(ViewStyle.Tile);
        }

        private void UpdateStyleMenuState(ViewStyle style)
        {
            if (style == ViewStyle.Tile)
                imageListView.SetRenderer(new ImageListViewRenderers.TilesRenderer());
            else
                imageListView.SetRenderer(new ImageListViewRenderers.DefaultRenderer());

            basicStyleToolStripMenuItem.Checked = (style == ViewStyle.Basic);
            tilesStyleToolStripMenuItem.Checked = (style == ViewStyle.Tile);

            settings.Style = style;
            settings.Save();
        }

        // 썸네일 크기 설정
        private void thumb36ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size36);
        }

        private void thumb48ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size48);
        }

        private void thumb72ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size72);
        }

        private void thumb96ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size96);
        }

        private void thumb120ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size120);
        }

        private void thumb144ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size144);
        }

        private void thumb168ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size168);
        }

        private void thumb192ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateThumbSizeMenuState(ThumbSize.Size192);
        }

        private void UpdateThumbSizeMenuState(ThumbSize size)
        {
            imageListView.ThumbnailSize = new Size((int)size, (int)size);

            thumb36ToolStripMenuItem.Checked = x36ToolStripMenuItem.Checked = (size == ThumbSize.Size36);
            thumb48ToolStripMenuItem.Checked = x48ToolStripMenuItem.Checked = (size == ThumbSize.Size48);
            thumb72ToolStripMenuItem.Checked = x72ToolStripMenuItem.Checked = (size == ThumbSize.Size72);
            thumb96ToolStripMenuItem.Checked = x96ToolStripMenuItem.Checked = (size == ThumbSize.Size96);
            thumb120ToolStripMenuItem.Checked = x120ToolStripMenuItem.Checked = (size == ThumbSize.Size120);
            thumb144ToolStripMenuItem.Checked = x144ToolStripMenuItem.Checked = (size == ThumbSize.Size144);
            thumb168ToolStripMenuItem.Checked = x168ToolStripMenuItem.Checked = (size == ThumbSize.Size168);
            thumb192ToolStripMenuItem.Checked = x192ToolStripMenuItem.Checked = (size == ThumbSize.Size192);

            settings.ThumbnailSize = size;
            settings.Save();
        }

        // 설정
        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (SettingsForm settingsForm = new SettingsForm(settings))
            {
                if (settingsForm.ShowDialog() == DialogResult.OK)
                {
                    ExpandNode(settings.Path);
                }
            }
        }

        // 개인 정보 검색 시스템
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (AboutForm aboutForm = new AboutForm())
            {
                aboutForm.ShowDialog();
            }
        }

        // 이미지 리스트 아이템 더블 클릭
        private void imageListView_ItemDoubleClick(object sender, ItemClickEventArgs e)
        {
            RunIfFileExists((path) => Process.Start(path), e.Item);
        }

        // 이미지 리스트 아이템 컨텍스트 메뉴 - 연결된 프로그램 실행하기
        private void runToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (imageListView.SelectedItems.Count > 1)
            {
                string msg = "여러 개의 파일을 선택하였습니다. 각 파일에 연결된 프로그램을 실행할까요?";

                if (MessageBox.Show(msg, "여러 개의 파일 선택", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
                    return;
            }

            foreach (var item in imageListView.SelectedItems)
            {
                RunIfFileExists((path) => Process.Start(path), item);
            }
        }

        // 이미지 리스트 아이템 컨텍스트 메뉴 - 파일이 포함된 폴더 열기
        private void openFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (imageListView.SelectedItems.Count > 1)
            {
                string msg = "여러 개의 파일을 선택하였습니다. 각 파일이 포함된 폴더를 열까요?";

                if (MessageBox.Show(msg, "여러 개의 파일 선택", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
                    return;
            }

            foreach (var item in imageListView.SelectedItems)
            {
                RunIfFileExists((path) => Process.Start("explorer.exe", @"/select," + path), item);
            }
        }

        // 이미지 리스트 아이템 컨텍스트 메뉴 - 속성
        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (imageListView.SelectedItems.Count > 1)
            {
                string msg = "여러 개의 파일을 선택하였습니다. 각 파일에 대한 속성을 열까요?";

                if (MessageBox.Show(msg, "여러 개의 파일 선택", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
                    return;
            }

            foreach (var item in imageListView.SelectedItems)
            {
                RunIfFileExists((path) => ShowFilePropertyDlg(path), item);
            }
        }

        private void RunIfFileExists(Action<string> action, ImageListViewItem item)
        {
            if (File.Exists(item.FileName))
            {
                action(item.FileName);
            }
            else
            {
                string msg = String.Format("파일 '{0}'을 찾을 수 없습니다", item.FileName);
                MessageBox.Show(msg, "실패", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                RemoveImageListViewItem(item);
            }
        }

        // 이미지 리스트 아이템에 마우스 포인터 올릴 시 툴팁으로 이미지 정보 보임
        private void imageListView_ItemHover(object sender, ItemHoverEventArgs e)
        {
            if (e.Item != null)
            {
                List<string> info = new List<string>();

                info.Add("파일이름: " + e.Item.FileName);
                info.Add("파일크기: " +
                    (e.Item.FileSize > 1024 * 1024 ? String.Format("{0:f}M", e.Item.FileSize / 1024.0 / 1024) :
                    e.Item.FileSize > 1024 ? String.Format("{0:f}K", e.Item.FileSize / 1024.0) :
                    e.Item.FileSize.ToString()));
                info.Add("생성시간: " + e.Item.DateCreated);
                info.Add("수정시간: " + e.Item.DateModified);
                if (!e.Item.Dimensions.IsEmpty)
                    info.Add("사진크기: " + e.Item.Dimensions.Width + "px x " + e.Item.Dimensions.Height + "px");
                if (!e.Item.Resolution.IsEmpty)
                    info.Add("해상도: " + e.Item.Resolution.Width + "dpi x " + e.Item.Resolution.Height + "dpi");

                propertiesToolTip.SetToolTip(imageListView, String.Join("\r\n", info));
            }
            else
            {
                propertiesToolTip.SetToolTip(imageListView, null);
            }
        }

        // notifyIconContextMenu 열기
        private void openTrayToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Visible = true;
            if (this.WindowState == FormWindowState.Minimized)
                this.WindowState = FormWindowState.Normal;
            this.Activate();
        }
        #endregion

        #region 파일 속성 다이얼로그
        // 파일 속성 다이얼로그를 보여줌
        // 참고: http://www.news2news.com/vfp/?example=320&ver=vcs&PHPSESSID=db5dae61d37478289d1ae7ff87b96093

        const int SEE_MASK_INVOKEIDLIST = 0x00000C;
        const int SEE_MASK_NOCLOSEPROCESS = 0x000040;
        const int SEE_MASK_FLAG_NO_UI = 0x000400;

        [StructLayout(LayoutKind.Sequential)]
        struct SHELLEXECUTEINFO
        {
            internal int cbSize;
            internal uint fMask;
            internal IntPtr hwnd;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpVerb;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpFile;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpParameters;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpDirectory;
            internal int nShow;
            internal IntPtr hInstApp;
            internal IntPtr lpIDList;
            [MarshalAs(UnmanagedType.LPWStr)]
            internal string lpClass;
            internal IntPtr hkeyClass;
            internal uint dwHotKey;
            internal IntPtr hIcon;
            internal IntPtr hProcess;
        }

        void ShowFilePropertyDlg(string path)
        {
            SHELLEXECUTEINFO info = new SHELLEXECUTEINFO();
            info.cbSize = Marshal.SizeOf(info);
            info.hwnd = IntPtr.Zero;
            info.fMask = (SEE_MASK_INVOKEIDLIST | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI);
            info.lpVerb = "properties";
            info.lpFile = path;

            ShellExecuteEx(ref info);
        }

        [DllImport("shell32.dll", SetLastError = true, EntryPoint = "ShellExecuteExW", CharSet = CharSet.Unicode)]
        static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);
        #endregion
    }
}